package cn.jasonone.ueditor.upload;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

import org.apache.commons.io.FileUtils;

import com.baidu.ueditor.PathFormat;
import com.baidu.ueditor.define.AppInfo;
import com.baidu.ueditor.define.BaseState;
import com.baidu.ueditor.define.State;
import com.baidu.ueditor.upload.IStorageManager;

import cn.jasonone.ueditor.UeditorProperties;
import cn.jasonone.ueditor.storage.LocationFileStorage;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
/**
 * 持久化管理类
 * @author Jason
 *
 */
@Slf4j
public class StorageManager implements IStorageManager, Config {
	public static final int BUFFER_SIZE = 8192;
	@Getter
	private static UeditorStorage upload;
	@Setter
	private UeditorProperties properties;

	public StorageManager() {
		upload = new LocationFileStorage();
	}

	public StorageManager(UeditorStorage upload) {
		if (upload == null) {
			upload = new LocationFileStorage();
		} else {
			StorageManager.upload = upload;
		}
	}

	/**
	 * 保存二进制数据到文件
	 * 
	 * @param data     二进制数据
	 * @param rootPath 根目录
	 * @param savePath 保存文件路径
	 * @return {@link State 状态对象}
	 */
	@Override
	public State saveBinaryFile(byte[] data, String rootPath, String savePath) {
		File file = new File(rootPath, savePath);
		State state = upload.validFile(savePath);
		log.trace("检测目录[{}]是否拥有写权限:{}", savePath, state.isSuccess());
		if (!state.isSuccess()) {
			return state;
		}

		try {
			upload.save(data, rootPath, savePath);
			log.trace("保存文件成功:{}", file.getAbsoluteFile());
		} catch (IOException ioe) {
			state = new BaseState(false, AppInfo.IO_ERROR);
			state.putInfo("path", file.getAbsolutePath());
			state.putInfo("size", data.length);
			state.putInfo("title", file.getName());
			log.error(state.toString(), ioe);
			return state;
		}
		state = new BaseState(true, file.getAbsolutePath());
		state.putInfo("url",properties.getBaseImageUrl()+PathFormat.format(savePath));
		state.putInfo("size", data.length);
		state.putInfo("title", file.getName());
		return state;
	}

	/**
	 * 保存输入流中数据到文件
	 * 
	 * @param is       输入流
	 * @param rootPath 根目录
	 * @param savePath 保存文件路径
	 * @param maxSize  最大文件长度
	 * @return {@link State 状态对象}
	 */
	@Override
	public State saveFileByInputStream(InputStream is, String rootPath, String savePath, long maxSize) {
		State state = null;
		File tmpFile = getTmpFile();
		byte[] dataBuf = new byte[2048];
		BufferedInputStream bis = new BufferedInputStream(is, StorageManager.BUFFER_SIZE);
		try {
			BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tmpFile),
					StorageManager.BUFFER_SIZE);
			int count = 0;
			while ((count = bis.read(dataBuf)) != -1) {
				bos.write(dataBuf, 0, count);
			}
			bos.flush();
			bos.close();
			if (tmpFile.length() > maxSize) {
				tmpFile.delete();
				return new BaseState(false, AppInfo.MAX_SIZE);
			}
			state = saveTmpFile(tmpFile, rootPath, savePath);
			state.putInfo("url", properties.getBaseImageUrl()+PathFormat.format(savePath));
			if (!state.isSuccess()) {
				tmpFile.delete();
			}
			return state;

		} catch (IOException e) {
		}
		return new BaseState(false, AppInfo.IO_ERROR);
	}
	/**
	 * 保存输入流中数据到文件
	 * 
	 * @param is       输入流
	 * @param rootPath 根目录
	 * @param savePath 保存文件路径
	 * @return {@link State 状态对象}
	 */
	@Override
	public State saveFileByInputStream(InputStream is, String rootPath, String savePath) {
		State state = null;
		File tmpFile = getTmpFile();
		try {
			BufferedInputStream bis = new BufferedInputStream(is, StorageManager.BUFFER_SIZE);
			byte[] dataBuf = new byte[2048];
			BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tmpFile),
					StorageManager.BUFFER_SIZE);

			int count = 0;
			while ((count = bis.read(dataBuf)) != -1) {
				bos.write(dataBuf, 0, count);
			}
			bos.flush();
			bos.close();
			state = saveTmpFile(tmpFile, rootPath, savePath);
			state.putInfo("url", properties.getBaseImageUrl()+PathFormat.format(savePath));
			if (!state.isSuccess()) {
				tmpFile.delete();
			}

			return state;
		} catch (IOException e) {
		}
		return new BaseState(false, AppInfo.IO_ERROR);
	}
	/**
	 * 创建临时文件
	 * @return {@link File 文件对象}
	 */
	private static File getTmpFile() {
		File tmpDir = FileUtils.getTempDirectory();
		String tmpFileName = (Math.random() * 10000 + "").replace(".", "");
		return new File(tmpDir, tmpFileName);
	}

	/**
	 * 将临时文件进行转存
	 * 
	 * @param tmpFile  临时文件
	 * @param rootPath 根目录
	 * @param path     文件路径
	 * @return {@link State 状态对象}
	 */
	private static State saveTmpFile(File tmpFile, String rootPath, String path) {
		State state = null;
		File targetFile = new File(path);
		state = upload.validFile(path);
		log.trace("检测目录[{}]是否拥有写权限:{}", path, state.isSuccess());
		if (!state.isSuccess()) {
			return state;
		}
		try {
			upload.save(tmpFile, rootPath, path);
			log.trace("保存文件成功:{}", targetFile.getAbsoluteFile());
		} catch (IOException e) {
			state = new BaseState(false, AppInfo.IO_ERROR);
			state.putInfo("path", targetFile.getAbsolutePath());
			state.putInfo("size", tmpFile.length());
			state.putInfo("title", targetFile.getName());
			log.error(state.toString(), e);
			return state;
		}

		state = new BaseState(true);
		state.putInfo("size", targetFile.length());
		state.putInfo("title", targetFile.getName());

		return state;
	}

	@Override
	public void setConfig(Map<String, Object> conf) {
		upload.setConfig(conf);
	}

}
